
package sanshui.system.trade.factory.trade.strategy.impl;

import com.alibaba.fastjson.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import sanshui.system.trade.common.GlobalContain;
import sanshui.system.trade.common.TradeType;
import sanshui.system.trade.db.entity.TradeLimitOrder;
import sanshui.system.trade.db.entity.TradeWorker;
import sanshui.system.trade.db.mapper.TradeLimitOrderMapper;
import sanshui.system.trade.factory.data.Bar;
import sanshui.system.trade.factory.trade.TradeSystemContext;
import sanshui.system.trade.factory.trade.indicator.IndicatorResult;
import sanshui.system.trade.factory.trade.strategy.AbstractStrategy;
import sanshui.system.trade.factory.trade.strategy.StrategyCallType;
import sanshui.system.trade.factory.trade.strategy.StrategyCode;
import sanshui.system.trade.factory.trade.strategy.StrategyResult;
import sanshui.system.trade.factory.trade.strategy.param.GridStrategyParam;
import sanshui.system.trade.model.PositionAccModel;
import sanshui.system.trade.model.TradeLimitOrderModel;
import sanshui.system.trade.service.ITradeLimitOrderService;
import sanshui.system.trade.service.IWorkerService;
import sanshui.system.trade.util.CommonTimeUtil;
import sanshui.system.trade.util.IdWorkerUtil;

import javax.annotation.Resource;
import javax.xml.crypto.Data;
import java.time.LocalDateTime;
import java.util.*;

/**
 * 默认使用A股
 * */
@Component
public class GridStrategy extends AbstractStrategy {
    private static final Logger logger = LoggerFactory.getLogger(GridStrategy.class);

    @Resource
    ITradeLimitOrderService tradeLimitOrderService;
    @Resource
    IWorkerService workerService;

    @Resource
    IdWorkerUtil idWorkerUtil;

    @Override
    public StrategyCode getStrategyCode() {
        return StrategyCode.GRID;
    }

    @Override
    public StrategyResult exec(String code, IndicatorResult indicatorResult, TradeSystemContext tradeSystemContext) {
        StrategyResult strategyResult = new StrategyResult();
        strategyResult.setCode(code);

        Bar bar = tradeSystemContext.getDataCache().getcurrentBar().get(code);
        Map<String, List<TradeLimitOrderModel>> limitOrderMap =
                tradeSystemContext.getLimitOrderMap();

        List<TradeLimitOrderModel> allLimitOrderList;

        Long accId = tradeSystemContext.getAccId();
        Long workerId = tradeSystemContext.getWorkerId();
        Long opNum = 0L;
        if (limitOrderMap.get(code) == null ||  limitOrderMap.get(code).size() == 0){
            allLimitOrderList = tradeLimitOrderService.findAllLimitOrderList(accId, workerId);
            if (allLimitOrderList.size() > 0) {
                limitOrderMap.put(code, allLimitOrderList);
            } else {
                // 初始化
                // 网格一定有限价单
                logger.info("网格初始化...");
                allLimitOrderList = this.computeGrid(code, tradeSystemContext);
                for (TradeLimitOrderModel model : allLimitOrderList) {
                    logger.info("limit-num:{}, price:{}, type:{}", model.getLimitNum(), model.getLimitPrice(), model.getOpType());
                    model.setLimitId(idWorkerUtil.nowId(IdWorkerUtil.IdType.LIMIT_ID));
                    tradeLimitOrderService.insertLimitOrderSelective(model);
                }
                limitOrderMap.put(code, allLimitOrderList);
                // 当前如果没有持仓，属于是第一次触发，需要把买入后面要卖出的数量
                PositionAccModel positionAccModel = tradeSystemContext.getHoldPositionMap().get(code);
                if (positionAccModel == null || positionAccModel.getNumTotal() == 0){
                    for (TradeLimitOrderModel model : allLimitOrderList) {
                        if (model.getOpType().equalsIgnoreCase(StrategyCallType.SELL.name())) {
                            opNum += model.getLimitNum();
                        }
                    }
                    strategyResult.setStrategyCallType(StrategyCallType.BUY);
                }
            }
        } else {
            allLimitOrderList = limitOrderMap.get(code);
        }

        List<TradeLimitOrderModel> opOrders = new ArrayList<>();
        PositionAccModel positionAccModel = tradeSystemContext.getHoldPositionMap().get(code);
        if (positionAccModel != null){
            opOrders = this.findNeedOpOrder(bar, allLimitOrderList);
            for (TradeLimitOrderModel opOrder : opOrders) {
                opNum += opOrder.getLimitNum();
                String opType = opOrder.getOpType();
                logger.info("命中-当前:{}, num:{}, price:{}, type:{}", bar.getClose(), opOrder.getLimitNum(), opOrder.getLimitPrice(), opOrder.getOpType());
                if (StrategyCallType.BUY.name().equalsIgnoreCase(opType)){
                    strategyResult.setStrategyCallType(StrategyCallType.BUY);
                    // 下跌超过限价更新为卖出
                    opOrder.setOpType(StrategyCallType.SELL.name());
                    tradeLimitOrderService.updateLimitOrderSelective(opOrder);
                } else if (StrategyCallType.SELL.name().equalsIgnoreCase(opType)){
                    strategyResult.setStrategyCallType(StrategyCallType.SELL);
                    // 上涨超过限价更新为买入
                    opOrder.setOpType(StrategyCallType.BUY.name());
                    tradeLimitOrderService.updateLimitOrderSelective(opOrder);
                }
            }
        }

        // 更新缓存
        for (TradeLimitOrderModel opOrder : opOrders) {
            for (TradeLimitOrderModel model : allLimitOrderList) {
                if (Objects.equals(opOrder.getLimitId(), model.getLimitId()) &&
                        !opOrder.getOpType().equalsIgnoreCase(model.getOpType())){
                    // 发现限价的交易状态不同，更新
                    model.setOpType(opOrder.getOpType());
                }
            }
        }
        limitOrderMap.put(code, allLimitOrderList);

        strategyResult.setNumAround(1L);
        strategyResult.setPriceAround(100L);
        // 最好是给与最新价格
        strategyResult.setPrice(bar.getClose());
        strategyResult.setNum(opNum);
        if (null == strategyResult.getStrategyCallType()){
            strategyResult.setStrategyCallType(StrategyCallType.NOTHING);
        }
        return strategyResult;
    }

    private List<TradeLimitOrderModel> computeGrid(String code, TradeSystemContext tradeSystemContext){
        List<TradeLimitOrderModel> rsl = new ArrayList<>();
        Bar bar = tradeSystemContext.getDataCache().getcurrentBar().get(code);
        Long workerId = tradeSystemContext.getWorkerId();
        Long accId = tradeSystemContext.getAccId();
        LocalDateTime now = tradeSystemContext.getTimeManager().timestampCurrent;

        TradeWorker tradeWorker = workerService.selectWorkerById(workerId);
        String strategyParam = tradeWorker.getStrategyParam();
        GridStrategyParam param = JSONObject.parseObject(strategyParam, GridStrategyParam.class);

        int execPrice = param.getExecPrice();
        int maxPrice = param.getMaxPrice();
        int minPrice = param.getMinPrice();
        int gridNum = param.getGridNum();
        int initValue = param.getInitValue();

        if (execPrice == 0){
            execPrice = bar.getClose().intValue();
        }

        int gridDelta = (maxPrice - minPrice) / gridNum;
        int willUsedCash = 0;
        List<Integer> allGrid = new ArrayList<>();
        for (int i = 0; i < gridNum; i++) {
            int grid = minPrice + i * gridDelta;
            if (grid >= maxPrice){
                grid = maxPrice;
            }
            willUsedCash += grid;
            allGrid.add(grid);
        }

        int canTradeNum = 0;
        while (initValue >= willUsedCash * (canTradeNum + 100)){
            canTradeNum += 100;
        }

        for (Integer grid : allGrid) {
            TradeLimitOrderModel model = new TradeLimitOrderModel();
            model.setLimitPrice(Long.valueOf(grid));
            model.setAccId(accId);
            model.setWorkerId(workerId);
            model.setTargetCode(code);
            model.setPhyFlg(TradeType.DelFlg.EXIT.getCode());
            model.setLimitNum((long) canTradeNum);
            model.setCreateTime(new Date());
            if (grid < execPrice){
                model.setOpType(StrategyCallType.BUY.name());
            }

            if (grid > execPrice){
                model.setOpType(StrategyCallType.SELL.name());
            }
            rsl.add(model);
        }

        return rsl;
    }

    private List<TradeLimitOrderModel> findNeedOpOrder(Bar bar, List<TradeLimitOrderModel> limitOrders){
        Long close = bar.getClose();
        List<TradeLimitOrderModel> needOp = new ArrayList<>();

        for (TradeLimitOrderModel limitOrder : limitOrders) {
            Long limitPrice = limitOrder.getLimitPrice();
            String opType = limitOrder.getOpType();
            if (close > limitPrice){
                if (opType.equalsIgnoreCase(StrategyCallType.SELL.name())){
                    // 上涨超过了限价，卖出
                    needOp.add(limitOrder);
                }
            }
            if (close < limitPrice){
                if (opType.equalsIgnoreCase(StrategyCallType.BUY.name())){
                    // 下跌超过了限价，买入
                    needOp.add(limitOrder);
                }
            }
        }
        return needOp;
    }
}
